package it.asvp.asvp_portal.service.services.impl;

import it.asvp.asvp_portal.asvp_util.enumerative.RoleName;
import it.asvp.asvp_portal.asvp_util.util.DateUtils;
import it.asvp.asvp_portal.data.dao.MemberAccountDao;
import it.asvp.asvp_portal.data.dao.MemberAccountRoleDao;
import it.asvp.asvp_portal.data.dao.MemberAccountUpdateDao;
import it.asvp.asvp_portal.data.dao.MemberDao;
import it.asvp.asvp_portal.data.dao.RoleDao;
import it.asvp.asvp_portal.data.entity.member.Member;
import it.asvp.asvp_portal.data.entity.member.MemberAccount;
import it.asvp.asvp_portal.data.entity.member.MemberAccountRole;
import it.asvp.asvp_portal.data.entity.member.MemberAccountUpdate;
import it.asvp.asvp_portal.data.entity.member.Role;
import it.asvp.asvp_portal.service.services.MemberAccountService;
import it.asvp.asvp_portal.service.util.Operation;
import it.asvp.asvp_portal.service.util.Permission;

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MemberAccountServiceImpl implements  MemberAccountService{

	@Autowired
	MemberDao memberDao;
	@Autowired
	MemberAccountDao memberAccountDao;
	@Autowired
	MemberAccountRoleDao memberAccountRoleDao;
	@Autowired
	MemberAccountUpdateDao memberAccountUpdateDao;
	@Autowired
	RoleDao roleDao;
	
	@Transactional
	public boolean isMember(Long idAccount){
	try{
		
		Role roleMax=Role.getMax(getRoles(idAccount));
		if(RoleName.SOCIO.equals(roleMax.getRoleName().getName())){
			return true;
		}
	}catch(Exception e){
		  return false;
	  }
		return false;
	}
	
	@Transactional
	public boolean isCouncilor(Long idAccount){
	try{
		
		Role roleMax=Role.getMax(getRoles( idAccount));
		if(RoleName.CONSIGLIERE.equals(roleMax.getRoleName().getName())){
			return true;
		}
		
	}catch(Exception e){
		  return false;
	  }
		return false;
	}
	
	@Transactional
	public boolean isPresident(Long idAccount){
	try{
		
        Role roleMax=Role.getMax(getRoles( idAccount));
		if(RoleName.PRESIDENTE.equals(roleMax.getRoleName().getName())){
			return true;
		}
		
	}catch(Exception e){
		  return false;
	  }
	
		return false;
	}
	
	@Transactional
	public boolean isAdmin(Long idAccount){
	  try{
		  
		 Role roleMax=Role.getMax(getRoles( idAccount));
		 if(RoleName.ADMIN.equals(roleMax.getRoleName().getName())){
				return true;
		 }
		 
	  }catch(Exception e){
		  return false;
	  }
		 return false;	
			
	}
	
	@Transactional
	public Set<Role> getRoles(Long idAccount) throws Exception{
		
		MemberAccount persistentMemberAccount=memberAccountDao.findById(idAccount);
		
		if(persistentMemberAccount==null){
			throw new Exception("Account errato");
		}
		Set<MemberAccountRole> memberAccountRoles=persistentMemberAccount.getMemberAccountRoles();
		Set<Role> roles=new HashSet<Role>();
		for(MemberAccountRole memberAccountRole:memberAccountRoles){
			roles.add(memberAccountRole.getRole());
		}
		return roles;
	}
	
	
	@Transactional
	public MemberAccount createAccount(Long idCurrentAccount,MemberAccount transientMemberAccount,RoleName roleName) throws Exception{
		
		 MemberAccount persistentCurrentAccount=memberAccountDao.findById(idCurrentAccount);
		 Role roleToAdd=roleDao.findByRoleName(roleName);
		  
		  if(persistentCurrentAccount==null){
				throw new Exception("Account errato");
			}
		  
		Role roleMax=Role.getMax(getRoles(idCurrentAccount));
		
        if(!Permission.checkPermission(roleMax, roleToAdd, Operation.CREATE)){
        	throw new Exception("non possiede i diritti necessari per aggiungere questo permesso");
        }
		
		transientMemberAccount.setCreatedOn(DateUtils.getCurrentDate());
		transientMemberAccount.setLastUpdate(DateUtils.getCurrentDate());
		Long id=memberAccountDao.persist(transientMemberAccount);
		addAccountUpdated(persistentCurrentAccount.getId(),id);
		addRole(id,roleToAdd.getRoleName());
		
		return null;
	}
	
	@Transactional
	public MemberAccount createAccountByEmail(Long idCurrentAccount,MemberAccount transientMemberAccount,String email,RoleName roleName) throws Exception{
		
		Member persistentMember=memberDao.findByEmail(email);
		if(persistentMember==null){
			throw new Exception("Socio non esistente");
		}
		
		if(memberAccountDao.findByMember(persistentMember)!=null){
			throw new Exception("Account gia esistente");
		}
		
		transientMemberAccount.setMember(persistentMember);
		return createAccount(idCurrentAccount,transientMemberAccount,roleName);
	}
	
	@Transactional
	public void updateAccount(Long idCurrentAccount,Long oldAccountId,MemberAccount newAccount) throws Exception{
		
		 MemberAccount persistentCurrentAccount=memberAccountDao.findById(idCurrentAccount);
		 MemberAccount persistentOldAccount=memberAccountDao.findById(oldAccountId);
		  
		  if(persistentCurrentAccount==null || persistentOldAccount==null){
				throw new Exception("Account errato");
			}
		  
		Role roleMax1=Role.getMax(getRoles(idCurrentAccount));
		Role roleMax2=Role.getMax(getRoles(oldAccountId));
		
        if(!Permission.checkPermission(roleMax1, roleMax2, Operation.UPDATE)){
        	throw new Exception("non possiede i diritti necessari per questa operazione");
        }
        
        persistentOldAccount.setLogin(newAccount.getLogin());
        persistentOldAccount.setPassword(newAccount.getPassword());
        persistentOldAccount.setExpireDate(newAccount.getExpireDate());
        persistentOldAccount.setLastUpdate(DateUtils.getCurrentDate());
        memberAccountDao.merge(persistentOldAccount);
	}
	
	@Transactional
	public void removeAccountRole(Long idCurrentAccount,Long idAccount,RoleName roleName) throws Exception{
		
		 MemberAccount persistentCurrentAccount=memberAccountDao.findById(idCurrentAccount);
		 MemberAccount persistentAccount=memberAccountDao.findById(idAccount);
		 Role roleToRemove=roleDao.findByRoleName(roleName);
		  
		  if(persistentCurrentAccount==null || persistentAccount==null){
				throw new Exception("Account errato");
			}
		  
		Role roleMax1=Role.getMax(getRoles(idCurrentAccount));
		Role roleMax2=Role.getMax(getRoles(idAccount));
		
        if(!(Permission.checkPermission(roleMax1, roleMax2, Operation.DELETE) && Permission.checkPermission(roleMax1, roleToRemove, Operation.DELETE))){
        	throw new Exception("non possiede i diritti necessari per questa operazione");
        }
        
        removeRole(idAccount,roleToRemove.getRoleName());
	}
	
	@Transactional
	public void deleteAccount(Long idCurrentAccount,Long idAccountToDelete) throws Exception{
		
	  MemberAccount persistentCurrentAccount=memberAccountDao.findById(idCurrentAccount);
	  MemberAccount persistentAccountToDelete=memberAccountDao.findById(idAccountToDelete);
	  
	  if(persistentCurrentAccount==null || persistentAccountToDelete==null){
			throw new Exception("Account errato");
		}
	  Role roleMax1=Role.getMax(getRoles(idCurrentAccount));
      Role roleMax2=Role.getMax(getRoles(idAccountToDelete));

      if(!Permission.checkPermission(roleMax1, roleMax2, Operation.DELETE)){
      	 throw new Exception("non possiede i diritti necessari per questa operazione");
      }
      
      memberAccountDao.delete(persistentAccountToDelete);
	}
	
	@Transactional
	public MemberAccount validateAccount(MemberAccount transientMemberAccount) throws Exception{
		
        MemberAccount persistentMemberAccount=memberAccountDao.findByLogin(transientMemberAccount.getLogin());
		
		if(persistentMemberAccount==null)
			throw new Exception("Account Errato");
		
		if(!persistentMemberAccount.getPassword().equalsIgnoreCase(transientMemberAccount.getPassword())){
			throw new Exception("Account Errato");
		}
		
		if(DateUtils.compare(DateUtils.getCurrentDate(),persistentMemberAccount.getExpireDate(), false) > 0){
			throw new Exception("Account scaduto");
		}	
		
		return persistentMemberAccount;
	}
	
	@Transactional
	public MemberAccount getAccountByMemberId(Long memberId) throws Exception{
		
		Member persistentMember=memberDao.findById(memberId);
		if(persistentMember==null){
			throw new Exception("Socio non esistente");
		}
		
		MemberAccount persistentMemberAccount=memberAccountDao.findByMember(persistentMember);
		if(persistentMemberAccount==null){
			throw new Exception("socio presente ma non avendo account associato");
		}
		return persistentMemberAccount;
	}
	
	@Transactional
	private void addAccountUpdated(Long idCurrentAccount,Long idAccountToAdd) throws Exception{
		
		MemberAccount persistentCurrentAccount=memberAccountDao.findById(idCurrentAccount);
		MemberAccount persistentAccountToAdd=memberAccountDao.findById(idAccountToAdd);
		
		if(persistentCurrentAccount==null || persistentAccountToAdd==null){
			throw new Exception("Account errato");
		}
		MemberAccountUpdate memberAccountUpdate=new MemberAccountUpdate();
		memberAccountUpdate.setCouncilor(persistentCurrentAccount.getMember()); 
		memberAccountUpdate.setMember(persistentAccountToAdd.getMember());
		
		//FIXME: cercare il modo di ottenere l'anno corrente
		memberAccountUpdate.setUpdateYear(2013); 
		memberAccountUpdate.setCreatedOn(DateUtils.getCurrentDate());
		memberAccountUpdate.setLastUpdate(DateUtils.getCurrentDate());
		MemberAccountUpdate persistentMemberAccountUpdate=memberAccountUpdateDao.findByYear(persistentAccountToAdd.getMember(),2013);
		
		if(persistentMemberAccountUpdate==null){
		      memberAccountUpdateDao.persist(memberAccountUpdate);
		}else{
			persistentMemberAccountUpdate.setLastUpdate(DateUtils.getCurrentDate());
			memberAccountUpdateDao.merge(persistentMemberAccountUpdate);
		}
	}
	
	@Transactional
	private void addRole(Long idAccount,RoleName roleName) throws Exception{
			
		MemberAccount persistentAccount=memberAccountDao.findById(idAccount);
        Role roleToAdd=roleDao.findByRoleName(roleName);
        
        if(persistentAccount==null){
        	throw new Exception("Account errato");
        }
        
		//controllo che il member non possieda gia il ruolo da aggiungere
		for(Role role:getRoles(idAccount)){
			if(role.compareTo(roleToAdd)==0){
				throw new Exception("diritti gia posseduti dal socio");
			}
		}
		
		//aggiungiamo il nuovo ruolo
		MemberAccountRole memberAccountRole=new MemberAccountRole();
		memberAccountRole.setMemberAccount(persistentAccount);
		memberAccountRole.setRole(roleToAdd);
		memberAccountRoleDao.persist(memberAccountRole);
	}
	
	@Transactional
	private void removeRole(Long idAccount,RoleName roleName) throws Exception{
			    
		        MemberAccount persistentAccount=memberAccountDao.findById(idAccount);
		        Role roleToRemove=roleDao.findByRoleName(roleName);
		        
		        if(persistentAccount==null){
		        	throw new Exception("Account errato");
		        }
		        
				//controllo che il member possieda il ruolo da rimuovere e lo rimuovo
		        Set<Role> roles=getRoles(idAccount);
		        if(roles.size()<=1){
		        	throw new Exception("puo solo aggiornare questo permesso perche' e' unico al socio");
		        }
		        
				for(Role role:roles){
					if(role.compareTo(roleToRemove)==0){
						MemberAccountRole memberAccountRole=memberAccountRoleDao.findBy(persistentAccount, roleToRemove);
						memberAccountRoleDao.delete(memberAccountRole);
						return;
					}
				}
				throw new Exception("il socio non possiede il diritti da rimuovere");
		
	}
		
}
